﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace TinySkill
{

    /// <summary>
    /// 技能关键帧处理器
    /// </summary>
    public class action_processor
    {
        protected Effect _effect;
        protected config_skill_frame _frame;
        public virtual void init(Effect effect, config_skill_frame frame) { _effect = effect; _frame = frame; }
        public virtual void begin() { }
        //如果结束，返回真
        public virtual bool update(int current_skill_frame) { return false; }
        public virtual void end() { }
        public config_skill_frame frame { get { return _frame; } }

        //不能移动？
        public virtual bool cant_move { get { return false; } }
        //不能旋转？
        public virtual bool cant_rotate { get { return false; } }
        //不能控制？
        public virtual bool cant_control { get { return false; } }

        //打断技能时调用
        public virtual void interrupt() { end(); }
    }


    /// <summary>
    /// 技能效果，用来执行技能逻辑
    /// </summary>
    public class Effect
    {
        public static Dictionary<SkillFrameAction, System.Type> ActionProcessors = new Dictionary<SkillFrameAction, Type>();

        protected float _timer;

        //当前执行到的action索引
        int current_frame_index = 0;
        //技能总action数
        int frame_action_count = 0;

        private Skill _skill;
        private config_skill _effect;

        private GameBattler _user;

        //施法者
        public GameBattler user
        {
            get
            {
                return _user;
            }
        }

        //技能
        public Skill skill
        {
            get
            {
                return _skill;
            }
        }

        //正在执行的action
        List<action_processor> frames = new List<action_processor>();

        private bool _start;
        private bool _end;

        //技能当前帧序号
        protected int frame_num;
        private List<action_processor> removed_frame = new List<action_processor>();    //删除用的一个缓冲空间

        bool jump = false;
        int jump_to_frame_index;


        public int loop_count;
        public bool _cancel_loop;

        static Effect()
        {
            ActionProcessors[SkillFrameAction.PLAY_SOUND] = typeof(action_play_sound);
        }

        public void Init(GameBattler u, Skill skill)
        {
            _user = u;
            _skill = skill;
            _effect = skill.data;
        }

        public bool cant_move
        {
            get
            {
                for (int i = 0; i < frames.Count; i++)
                {
                    if (frames[i].cant_move)
                        return true;
                }

                return false;
            }
        }

        public bool cant_rotate
        {
            get
            {
                for (int i = 0; i < frames.Count; i++)
                {
                    if (frames[i].cant_rotate)
                        return true;
                }

                return false;
            }
        }

        public bool cant_control
        {
            get
            {
                for (int i = 0; i < frames.Count; i++)
                {
                    if (frames[i].cant_control)
                        return true;
                }

                return false;
            }
        }

        public bool Update(float deltaTime)
        {
            if (!_start)
            {
                Start();
            }
            if (!_end && Tick(deltaTime))
            {
                End();
            }

            return _end;
        }

        public void Cancel_Loop()
        {
            _cancel_loop = true;
        }

        public void ForceEnd()
        {
            if (!_end)
            {
                for (int i = 0; i < frames.Count; i++)
                {
                    frames[i].interrupt();
                }
                _end = true;
            }

        }

        protected void Start() { _start = true; }
        protected void End()
        {
            _end = true;

            //防止技能被打断，某些特殊动作未完成
            for (int i = 0; i < frames.Count; i++)
            {
                frames[i].end();
            }
        }

        public int GetLoopedFrameLength(config_skill_frame f)
        {
            for (int i = 0; i < _effect.frames.Length; i++)
            {
                if (_effect.frames[i].action == SkillFrameAction.LOOP && _effect.frames[i].frame_index >= f.frame_index &&
                    _effect.frames[i].frame_index + _effect.frames[i].frame_length < f.frame_index + f.frame_length)
                {
                    config_action_loop data = (config_action_loop)_effect.frames[i].data;
                    return _effect.frames[i].frame_length * data.loop_count + f.frame_length;
                }
            }

            return f.frame_length;
        }

        bool UpdateLogic()
        {
            UnityEngine.Profiling.Profiler.BeginSample("UpdateEffectInitFrame");
            //关键帧开始判定
            while (_effect.frames != null && current_frame_index < _effect.frames.Length && frame_num > _effect.frames[current_frame_index].frame_index)
            {
                config_skill_frame sf = _effect.frames[current_frame_index];
                System.Type ap_type = null;
                if (ActionProcessors.TryGetValue(sf.action, out ap_type))
                {
                    UnityEngine.Profiling.Profiler.BeginSample("UpdateEffectInitFrame " + ap_type.Name);
                    action_processor ap = System.Activator.CreateInstance(ap_type) as action_processor;
                    frames.Add(ap);
                    ap.init(this, sf);
                    ap.begin();
                    UnityEngine.Profiling.Profiler.EndSample();
                    //ap.update(frame_num);
                }
                else
                {
                    action_processor ap = new action_processor();
                    frames.Add(ap);
                    ap.init(this, sf);
                    ap.begin();
                    //ap.update(frame_num);
                }

                current_frame_index++;
            }
            UnityEngine.Profiling.Profiler.EndSample();

            UnityEngine.Profiling.Profiler.BeginSample("UpdateEffectFrame");
            //关键帧更新
            for (int i = 0; i < frames.Count; i++)
            {
                int end_frame = frames[i].frame.frame_index + frames[i].frame.frame_length;


                //如果技能关键帧指示结束，移除关键帧
                if (frame_num < end_frame && frames[i].update(frame_num))
                {
                    frames[i].end();
                    removed_frame.Add(frames[i]);
                }
                //如果到了最后一帧，调用end方法
                else if (frame_num >= end_frame)
                {
                    frames[i].end();
                    removed_frame.Add(frames[i]);
                }
            }
            UnityEngine.Profiling.Profiler.EndSample();

            //关键帧结束
            for (int i = 0; i < removed_frame.Count; i++)
            {
                frames.Remove(removed_frame[i]);
            }
            removed_frame.Clear();


            //跳转帧
            if (jump)
            {
                JumpImplement(jump_to_frame_index);
                jump = false;
            }


            if (frame_num > _effect.frame_count && current_frame_index >= frame_action_count && frames.Count == 0)
            {
                return true;
            }

            return false;
        }

        //跳转到指定帧索引（外部调用）
        public void Jump(int frame_index)
        {
            jump = true;
            jump_to_frame_index = frame_index;
        }

        //跳转到指定帧索引
        void JumpImplement(int frame_index)
        {
            //要提前一帧，因为下一个循环，帧数自动+1
            frame_num = frame_index;
            bool found_key_frame = false;
            for (int i = 0; i < _effect.frames.Length; i++)
            {
                if (_effect.frames[i].frame_index >= frame_index)
                {
                    current_frame_index = i;
                    found_key_frame = true;
                    break;
                }
            }
            if (!found_key_frame)
            {
                current_frame_index = _effect.frames.Length;
            }
        }

        //每帧时长
        public const float FrameLength = 1.0f / 30.0f;

        //如果完成了，反回真
        protected bool Tick(float deltaTime)
        {
            _timer += deltaTime;
            while (_timer >= FrameLength)
            {
                _timer -= FrameLength;
                frame_num++;
                if (UpdateLogic())
                    return true;
            }
            return false;
        }
    }

}